﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using MapLibrary.Utility;
using MapLibrary.GUI;

namespace GUILibrary
{
    /// <summary>
    /// This represents an general bar that gets "filled" with respect to a reference
    /// to some value.
    /// </summary>
    public class HorizontalFillBar : Component, ActionListener
    {
        /// <summary>
        /// Unique identifier for each bar.  Used for nameing actions.
        /// </summary>
        public static int barId = 0;

        public delegate void BarFilledDelegate();

        /// <summary>
        /// This event gets triggered whenever the bar is full.  It is the
        /// responsibility of the listener to then act, possibly emptying the
        /// bar, etc.
        /// </summary>
        public event BarFilledDelegate OnBarFull;

        /// <summary>
        /// The underlying image of the bar.  This gets displayed under the
        /// fillImage.
        /// </summary>
        public string BaseImageName
        {
            get;
            set;
        }

        /// <summary>
        /// The image that will be repeated horizontally to represent "filling"
        /// the bar.
        /// </summary>
        public string FillImageName
        {
            get;
            set;
        }

        /// <summary>
        /// The offset in the base image where we will start drawing the horizontal
        /// bar.
        /// </summary>
        public Vector2 ProgressOffset
        {
            get;
            set;
        }

        /// <summary>
        /// How wide the "progress" area is.
        /// </summary>
        public int EffectiveWidth
        {
            get;
            set;
        }

        /// <summary>
        /// The value to track.  This value determines how full the bar is.
        /// </summary>
        [ContentSerializerIgnore]
        public int ValueToTrack
        {
            get { return ToTrack.GetAmount(Name); }
        }

        /// <summary>
        /// The maximum value for the tracked value.  This determines what percent full
        /// the bar is.
        /// </summary>
        [ContentSerializerIgnore]
        public int MaximumValue
        {
            get { return ToTrack.GetMax(Name); }
        }

        [ContentSerializerIgnore]
        public ITrackable ToTrack
        {
            get { return toTrack; }
            set
            {
                toTrack = value;
                CheckAndTriggerInitialize();
            }
        }

        private Texture2D baseImage;
        private Texture2D fillImage;
        private ITrackable toTrack;

        private int fillImageWidth;
        private TimerUtility fillTimer;

        public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch batch)
        {
            //draw the underlying bar at my position.
            batch.Draw(baseImage, ScreenPosition, Color.White);

            //now draw the fill amount
            float percent = CalculatePercent();
            int numBars = (int)((EffectiveWidth * percent) / fillImageWidth);
            Vector2 startPos = ScreenPosition + ProgressOffset;
            for (int i = 0; i < numBars; i++)
            {
                batch.Draw(fillImage, startPos + (i * new Vector2(fillImageWidth, 0)), Color.White);
            }
        }

        public override void Load(ContentManager cm)
        {
            Action = "HorizontalFillBar" + barId++;

            baseImage = cm.Load<Texture2D>(BaseImageName);
            fillImage = cm.Load<Texture2D>(FillImageName);
            fillImageWidth = fillImage.Bounds.Width;
        }

        private float CalculatePercent()
        {
            if (!Initialized)
                return 0.0f;
            else
            {
                return (float)ValueToTrack / MaximumValue;
            }
        }

        private void CheckAndTriggerInitialize()
        {
            bool initPrev = Initialized;
            Initialized = ToTrack != null;

            if (Initialized && !initPrev)
            {
                fillTimer = new TimerUtility(UpdateAmounts, (5 * 60) / MaximumValue);
            }
        }

        public void UpdateAction(List<string> currentActions)
        {
            if (currentActions.Count == 0)
                return;

            //note I only want to execute if I'm initialized.
            if (!Initialized)
                return;

            if (currentActions.Contains(Action))
            {
                //fill bar stuff
                fillTimer.Update();
            }
        }

        public override void UpdateMouseClick(Input.GameInput input)
        {
            Triggered = input.IsLeftMouseButtonDown() && Hovered;
        }

        private void UpdateAmounts()
        {
            if (ToTrack.GetSink(Name) > 0)
            {
                if (ToTrack.GetAmount(Name) < ToTrack.GetMax(Name))
                {
                    ToTrack.IncrimentValue(Name);
                    ToTrack.DecrimentSink(Name);
                }
            }
        }
    }
}
